package com.iuie.ns.datum.service.impl;

import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.iuie.ns.system.service.code.ISysCodeInfoService;
import com.iuie.ns.system.vo.code.SysCodeInfoVO;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.common.SolrInputDocument;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.stereotype.Service;

import com.github.pagehelper.PageHelper;
import com.iuie.ns.datum.dao.IBlogDao;
import com.iuie.ns.datum.mapper.BlogMapper;
import com.iuie.ns.datum.mapper.BlogReportMapper;
import com.iuie.ns.datum.service.IBlogService;
import com.iuie.ns.datum.service.IBlogSolrService;
import com.iuie.ns.datum.service.IFileInfoService;
import com.iuie.ns.datum.service.IFileService;
import com.iuie.ns.datum.vo.BlogInfoVO;
import com.iuie.ns.datum.vo.BlogReadRecordVO;
import com.iuie.ns.datum.vo.BookInfoVO;
import com.iuie.ns.datum.vo.FileInfoVO;
import com.iuie.ns.frame.config.AppConfigUtil;
import com.iuie.ns.frame.exception.FileDownloadException;
import com.iuie.ns.frame.exception.ServiceException;
import com.iuie.ns.frame.persistence.dao.IGenericDao;
import com.iuie.ns.frame.service.impl.BaseServiceImpl;
import com.iuie.ns.frame.utils.DateUtils;
import com.iuie.ns.frame.utils.ListUtils;
import com.iuie.ns.frame.utils.ShiroUtils;
import com.iuie.ns.frame.utils.StringUtils;
import com.iuie.ns.frame.utils.WebUtils;
import com.iuie.ns.frame.utils.ZipUtils;
import com.iuie.ns.frame.utils.callback.OnZipCompressCallback;
import com.iuie.ns.frame.web.dataset.vo.Page;
import com.iuie.ns.system.utils.QuickReportUtils;
import com.iuie.ns.system.utils.callback.QucikReportCallback;
import com.iuie.ns.system.vo.user.SysUserVO;

@Service("blogService")
public class BlogServiceImpl extends BaseServiceImpl<BlogInfoVO> implements IBlogService {

	@Resource
	private IBlogDao blogDao;

	@Resource
	private IFileInfoService fileInfoService;

	@Resource
	private IFileService fileService;

	@Resource
	private BlogMapper blogMapper;

	@Resource
	private IBlogSolrService blogSolrService;
	
	@Resource
	private BlogReportMapper blogReportMapper;


	@Override
	protected IGenericDao<BlogInfoVO, Serializable> getGenericDao() {
		return blogDao;
	}

	@Override
	public List<BlogInfoVO> findByBlogType(String blogType) {
		return blogMapper.findByBlogType(blogType);
	}



	@Override
	public BlogInfoVO addBlog(BlogInfoVO blogInfo) throws Exception {
		// fileId,blogType,author不能为空
		FileInfoVO fileInfo = null;
		if (blogInfo.getBlogName() == null) {
			throw new NullPointerException("博客名称不能为空");
		}
		blogInfo.setBlogAttr("0");
		blogInfo.setUpdateTime(new Date());
		fileInfo = createFileByUrl(blogInfo);
		//如果上传url
		if (blogInfo.getFileInfo() == null
				|| blogInfo.getFileInfo().getFileId() == null) {
			if (blogInfo.getLink() == null) {
				throw new NullPointerException("必须上传博客文件或设置博客的超链接");
			} else {
				// 验证本博客超链接是否合法
//				if (!URLUtil.isValid(blogInfo.getLink())) {
//					throw new ServiceException("不合法的超链接：" + blogInfo.getLink());
//				}
			}
			fileInfoService.addFileInfo(fileInfo, true);
			blogInfo.setFileInfo(fileInfo);
			
		}

		if (blogInfo.getBlogType() == null || blogInfo.getBlogType().getCodeInfoValue() == null) {
			throw new NullPointerException("博客类型不能为空");
		}
		SysUserVO user = (SysUserVO) ShiroUtils.getCurrentUser();
		// SysUserVO user = new SysUserVO();
		// user.setUserId("10000001");
		// user.setUserName("刘杰");
		if (user == null) {
			throw new ServiceException("当前登录用户异常，保存博客失败！");
		}
		blogInfo.setAuthor(user.getUserName());
		blogInfo.setAuthorId(user.getUserId());

		// 更新createTime为最新时间
		blogInfo.setCreateTime(new Date());
		BlogInfoVO uBlogInfo = null;
		if (blogInfo.getBlogId() == null) {
			// 新增博客
			blogInfo.setBlogId(StringUtils.timestampId());
			blogDao.addBlog(blogInfo);
			// 在上传文件的情况下，blogInfo.fileInfo.fileName = null
			// 而如果未上传文件，blogInfo.fileInfo.fileName = blogInfo.link
			if (blogInfo.getFileInfo().getFileName() == null) {
				fileService.letFileNameLegal(blogInfo.getFileInfo().getFileId());
			}
		} else {
			// 修改博客
			blogDao.updateBlog(blogInfo);
			uBlogInfo = blogInfo;
		}
		// 创建文件索引
		if(!WebUtils.isURL(fileInfo.getFileName())){
			blogSolrService.createSolrIndex(uBlogInfo);
		}
		
		return uBlogInfo;
	}


	@Resource
	private HibernateTransactionManager transactionManager;
	
	@Override
	public BlogInfoVO addMdBlog(BlogInfoVO blogInfo, FileInfoVO fileInfo) throws IOException, SolrServerException {
		
		blogInfo.setUpdateTime(new Date());
		blogInfo.setBlogAttr("1");
		blogInfo.setFileInfo(fileInfo);
		SysUserVO user = (SysUserVO) ShiroUtils.getCurrentUser();
		// SysUserVO user = new SysUserVO();
		// user.setUserId("10000001");
		// user.setUserName("刘杰");
		if (user == null) {
			throw new ServiceException("当前登录用户异常，保存博客失败！");
		}
		blogInfo.setAuthor(user.getUserName());
		blogInfo.setAuthorId(user.getUserId());
		// 更新createTime为最新时间
		blogInfo.setCreateTime(new Date());
		
		// 新增博客
		blogInfo.setBlogId(StringUtils.timestampId());
		blogDao.addBlog(blogInfo);
		
		// 创建文件索引
		if(!WebUtils.isURL(fileInfo.getFileName())){
			blogSolrService.createSolrIndex(blogInfo);
		}

		return blogInfo;
	}
	
	private String getTextByUrl(String link){
		String text = null;
		try {
			Connection conn = Jsoup.connect(link);
			Document doc = conn.timeout(100000).get();
			text = doc.text();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return text;
	}
	
	private FileInfoVO createFileByUrl(BlogInfoVO blogInfo) {
		FileInfoVO fileInfo = new FileInfoVO();
		long fileId = System.currentTimeMillis();
		fileInfo.setFileId(fileId);
		String text = getTextByUrl(blogInfo.getLink());
		
		writeFileByUrl(fileId, text);
		
		fileInfo.setFileName(fileId + ".txt");
		fileInfo.setOriginalName(blogInfo.getBlogName());
		fileInfo.setUploadTime(new Date());
		fileInfo.setFileType("blog");
		return fileInfo;
	}
	
	private void writeFileByUrl(long fileId, String text){
		BufferedWriter bufferedWriter = null;
		File file = null;
		try {
			String fileName = FileServiceImpl.BLOG_FILE_PATH + fileId + ".txt";
		    file = new File(fileName);
			bufferedWriter = new BufferedWriter(new FileWriter(file));
			bufferedWriter.write(text);
		} catch (IOException e) {
			if(file != null){
			   file.delete();
			}
			e.printStackTrace();
		} finally{
			if(bufferedWriter != null){
				try {
					bufferedWriter.close();
				} catch (IOException e) {
					e.printStackTrace();
				}  
			}
		}
	}

	@Override
	public void updateBySignRead(Long blogId) {
		SysUserVO user = (SysUserVO) ShiroUtils.getCurrentUser();
		long readId = System.currentTimeMillis();
		blogMapper.saveBlogRead(readId, Long.parseLong(user.getUserId()), blogId, new Date());
		blogMapper.updateBySignRead(blogId);
	}

	@Override
	public void deleteById(Long id) {
		// 1. 查询blogInfo
		// 2. 取出fileInfo
		BlogInfoVO blogInfo = blogMapper.findById((Long) id);
		FileInfoVO fileInfo = blogInfo.getFileInfo();
		// 3.删除文件索引
		try {
			blogSolrService.deleteBlogFileIndex("blog_id:" + id);
		} catch (Exception e) {
			e.printStackTrace();
			throw new ServiceException("删除文件索引失败");
		}
		// 4. 删除blogInfo
		// 5. 删除file和fileInfo
		blogMapper.deleteById(id);
		if (fileInfo != null) {
			fileService.deleteFileById(fileInfo.getFileId(), true);
		}

	}

	@Override
	public BlogInfoVO findById(Long id) {
		BlogInfoVO blogInfo = blogMapper.findById(id);
		if (blogInfo == null) {
			throw new ServiceException("博客已被删除！");
		}
		return blogInfo;
	}


	@Override
	public List<BlogInfoVO> findByBlogName(String blogName) {
		return blogMapper.findByBlogName(blogName);
	}

	@Override
	public void updateMdBlog(BlogInfoVO blogInfo) {
		blogInfo.setUpdateTime(new Date());
		blogMapper.updateMdBlog(blogInfo);
		//更新索引
        blogSolrService.createSolrIndex(blogInfo);
	}

	@Override
	public void mdDownload(String blogId, HttpServletResponse resp) throws IOException {
		BlogInfoVO blogInfo = blogMapper.findById(Long.valueOf(blogId));
		String fileName=new String(blogInfo.getBlogName().getBytes("UTF-8"),"iso-8859-1") + ".md";//为了解决中文名称乱码问题
        
		resp.setCharacterEncoding("utf-8");
        resp.setContentType("application/octet-stream");
        resp.setHeader("Content-Disposition", "form-data; name=\"attachment\";filename=\""+ fileName+"\"");
        
        if (StringUtils.isBlank(blogInfo.getMdContent())) {
			throw new ServiceException("markdown文档为空！");
		}
        
        byte[] mdBuffer = StringEscapeUtils.unescapeHtml(blogInfo.getMdContent()).getBytes("utf-8");
        ByteArrayInputStream bais = new ByteArrayInputStream(mdBuffer);
        
        OutputStream os = resp.getOutputStream();
		byte[] buffer = new byte[1024];
		int length;
		while((length = bais.read(buffer))>0){
			os.write(buffer, 0, length);
		}
		
		os.flush();
		os.close();
		bais.close();
	}
	
	public static final String TEMP_MARKDOWN_FILE_PATH = AppConfigUtil.getInstance().getProperty("file.uploads.temp.markdown");
	
	@Override
	public void mdPack(String startTime, String endTime, String[] expects, OutputStream os) throws ParseException {
		List<BlogInfoVO> list = this.findMDBlogByTimeRange(startTime, endTime, expects);
		
		if (list == null || list.size() <= 0) {
			throw new FileDownloadException("MDPackPage.onPackError", "没有查询到满足条件的markdown文档！");
		}
		
		ZipUtils.compressList(list, os, new OnZipCompressCallback<BlogInfoVO>() {

			@Override
			public void onError(Exception ex) {
				throw new FileDownloadException("MDPackPage.onPackError", "生成压缩文件失败，请联系管理员进行处理！");
			}

			@Override
			public String getContent(BlogInfoVO item) {
				return item.getMdContent();
			}

			@Override
			public String getFileName(BlogInfoVO item) {
				return item.getBlogName() + ".md";
			}
		});
	}

	@Override
	public List<BlogInfoVO> findMDBlogByTimeRange(String startTime, String endTime, String[] expects) throws ParseException {
		List<String> expectLst = null;
		if (expects != null && expects.length > 0) {
			expectLst = ListUtils.arrayToList(expects);
		}
		final String DATE_FORMAT = "yyyy-MM-dd";
		Date start = null;
		Date end = null;
		if (StringUtils.isBlank(startTime)) {
			start = DateUtils.strDateToPatternDate(DateUtils.getCurrTimeChangeNthDayDate(-6, DATE_FORMAT), DATE_FORMAT);
		} else {
			start = DateUtils.stringToDate(startTime, DATE_FORMAT);
		}
		if (StringUtils.isBlank(endTime)) {
			end = DateUtils.strDateToPatternDate(DateUtils.getCurrTimeChangeNthDayDate(1, DATE_FORMAT), DATE_FORMAT);
		} else {
			end = DateUtils.stringToDate(endTime, DATE_FORMAT);
		}
		SysUserVO user = (SysUserVO) ShiroUtils.getCurrentUser();
		if (user == null || StringUtils.isBlank(user.getUserId())) {
			throw new ServiceException("登录的用户信息为空！");
		}
		String userId = user.getUserId();
//		String userId = "10000001";
		return blogMapper.findMDBlogByTimeRange(start, end, expectLst, userId);
	}

	@Override
	public List<BlogReadRecordVO> findBlogReadbyIdPage(Page page, Long blogId) {
		PageHelper.startPage(page.getPage(), page.getRows(), true);
		List<BlogReadRecordVO> list = blogMapper.findReadRecodByBlogId(blogId);
		page.loadData(list);
		return list;
	}

	@Override
	public void updateBlogBookId(Long blogId, String bookId) {
		blogMapper.updateBlogBookId(blogId, bookId);
	}

	@Override
	public List<BookInfoVO> findBlogsByBookId(String bookId) {
		return blogMapper.findBlogsByBookId(bookId);
	}
	
	@Override
	public void updateMdBlogRemark(Long blogId, String remarks) {
		if (blogId == null) {
			throw new ServiceException("blogId 不能为空！");
		}
		blogMapper.updateMdBlogRemark(blogId, remarks);
	}
	
	@Override
	public String findRemarkById(Long blogId) {
		if (blogId == null) {
			throw new ServiceException("blogId 不能为空！");
		}
		BlogInfoVO blogInfo = blogMapper.findById(blogId);
		if (blogInfo == null) {
			return null;
		}
		return blogInfo.getRemarks();
	}
	
	@Override
	public void loadReadTotalReportData(Map<String, Object> params, HttpServletRequest request) {
		
		QuickReportUtils.handle(params, request, new QucikReportCallback() {
			
			@Override
			public List<Double> accordWeek(List<String> queryParams, String userId) {
				return blogReportMapper.findReadTotalReportDataWithWeek(queryParams, userId);
			}
			
			@Override
			public List<Double> accordMonth(List<String> queryParams, String userId) {
				return blogReportMapper.findReadTotalReportDataWithMonth(queryParams, userId);
			}
			
			@Override
			public List<Double> accordDay(List<String> queryParams, String userId) {
				return blogReportMapper.findReadTotalReportDataWithDay(queryParams, userId);
			}
		});
	}
	
}
